﻿using AutoMapper;
using lwzlz.Application.System.Dto;
using lwzlz.Common;
using lwzlz.Core;
using lwzlz.Core.Repository;
using System;
using System.Collections.Generic;
using System.Linq;

namespace lwzlz.Application.System
{
    /// <summary>
    /// 
    /// </summary>
    public class AuthorityService
    {
        private readonly IRepository<Menu> _repository;
        private readonly IRepository<RoleMenu> _roleRepository;
        private readonly IRepository<UserMenu> _userRepository;

        /// <summary>
        /// 
        /// </summary>
        public AuthorityService()
        {
            _repository = new Repository<Menu>();
            _roleRepository = new Repository<RoleMenu>();
            _userRepository = new Repository<UserMenu>();
        }

        #region 权限设置

        #region 获取角色权限列表
        public IEnumerable<RolePermissionOutput> GetRoleMenuTBs(int roleId)
        {
            // 获取菜单列表
            var menuList = GetMenuList();
            // 查询角色-菜单关联表
            var RoleMenuTBList = _roleRepository.GetList(new { RoleId = roleId });

            IEnumerable<RolePermissionOutput> menus = menuList.Where(m => m.MenuType == 1).Select(menu => // 菜单
                new RolePermissionOutput
                {
                    Id = menu.Id,
                    MenuName = ZString.ReplicateString("　　", menu.MenuDeep ?? 0) + "|—" + menu.MenuName,
                    IsEnable = RoleMenuTBList.Where(r => r.MenuId == menu.Id).Count() > 0,
                    ParentId = menu.ParentId,
                    ButtonList = menuList.Where(m => m.MenuType == 2 && m.ParentId == menu.Id).Select(btn => // 按钮
                        new SysButton
                        {
                            Id = btn.Id,
                            ButtonName = btn.MenuName,
                            IsEnable = RoleMenuTBList.Where(r => r.MenuId == btn.Id).Count() > 0,
                            ParentId = btn.ParentId,
                        })
                });

            return menus;
        }
        #endregion

        #region 保存角色权限
        public void SaveRolePermission(int roleId, IEnumerable<int> menuIds)
        {
            var dbtran = _roleRepository.BeginTransaction();
            try
            {
                // 删除原权限
                _roleRepository.DeleteList(new { RoleId = roleId }, dbtran);
                if (menuIds != null && menuIds.Count() > 0)
                {
                    // 添加新权限
                    foreach (int menuId in menuIds)
                    {
                        _roleRepository.Execute(
                            sql: $"INSERT INTO Sys_RoleMenu (RoleId, MenuId) VALUES ({roleId}, {menuId})",
                            transaction: dbtran);
                    }
                }
                dbtran.Commit();
            }
            catch (Exception)
            {
                dbtran.Rollback();
                throw;
            }
            finally
            {
                dbtran.Dispose();
            }
        }
        #endregion

        #region 用户权限

        /// <summary>
        /// 获取用户权限列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public IEnumerable<UserPermissionOutput> GetUserMenus(int userId)
        {
            // 获取菜单列表
            var menuList = GetMenuList();
            // 获取用户角色
            IEnumerable<UserRole> userRoles = _userRepository.Query<UserRole>(
                "SELECT * FROM Sys_UserRole WHERE UserId=@UserId", new { @UserId = userId });
            IEnumerable<RoleMenu> RoleMenuTBList = null; // 用户菜单列表
            if (userRoles != null && userRoles.Count() > 0)
            {
                string roleIds = "" // 角色Id
                    , douhao = "";  // 逗号分隔符
                foreach (var item in userRoles)
                {
                    roleIds += douhao + item.RoleId;
                    douhao = ",";
                }
                // 查询角色-菜单关联表
                RoleMenuTBList = _roleRepository.Query($"SELECT * FROM Sys_RoleMenu WHERE RoleId IN ({roleIds})");
            }   // ELSE 用户未设置角色

            // 查询用户-菜单关联表
            IEnumerable<UserMenu> UserMenuList = _userRepository.GetList(new { UserId = userId });

            IEnumerable<UserPermissionOutput> menus = menuList.Where(m => m.MenuType == 1).Select(menu => // 菜单
                {
                    bool isDisabled = false;
                    return new UserPermissionOutput
                    {
                        Id = menu.Id,
                        MenuName = ZString.ReplicateString("　　", menu.MenuDeep ?? 0) + "|—" + menu.MenuName,  // 菜单名缩进
                        IsEnable = CheckAuthorityStatus(RoleMenuTBList, UserMenuList, menu.Id, out isDisabled),    // 用户是否已有权限（包括角色赋予的）
                        IsDisabled = isDisabled,
                        ButtonList = menuList.Where(m => m.MenuType == 2 && m.ParentId == menu.Id).Select(btn => // 按钮
                            {
                                bool isBtnDisabled = false;
                                return new SysButton
                                {
                                    Id = btn.Id,
                                    ButtonName = btn.MenuName,
                                    IsEnable = CheckAuthorityStatus(RoleMenuTBList, UserMenuList, menu.Id, out isDisabled),
                                    IsDisabled = isBtnDisabled
                                };
                            })
                    };
                });

            return menus;
        }

        /// <summary>
        /// 判断用户、用户角色是否已有菜单权限
        /// </summary>
        /// <param name="RoleMenuTBList"></param>
        /// <param name="UserMenuList"></param>
        /// <param name="enumId"></param>
        /// <param name="isDisabled"></param>
        /// <returns></returns>
        protected bool CheckAuthorityStatus(IEnumerable<RoleMenu> RoleMenuTBList
            , IEnumerable<UserMenu> UserMenuList, int enumId, out bool isDisabled)
        {
            bool isEnable = false; // 是否有此权限
            isDisabled = false;    // 角色是否有此权限

            // 判断用户角色权限是否为空
            if (RoleMenuTBList != null && RoleMenuTBList.Count() > 0)
            {
                foreach (var item in RoleMenuTBList)
                {
                    if (enumId == item.MenuId)
                    {
                        // 用户角色有此权限
                        isEnable = true;
                        isDisabled = true;
                        return isEnable;
                    }
                }

                // 用户角色无此权限
                isDisabled = false;
                isEnable = CheckUserMenu(UserMenuList, enumId);
            }
            else
            {
                // 用户角色无此权限
                isDisabled = false;
                isEnable = CheckUserMenu(UserMenuList, enumId);
            }

            return isEnable;
        }

        /// <summary>
        /// 检测用户是否已有菜单权限
        /// </summary>
        /// <param name="UserMenuList"></param>
        /// <param name="enumId"></param>
        /// <returns></returns>
        protected bool CheckUserMenu(IEnumerable<UserMenu> UserMenuList, int enumId)
        {
            bool isEnable = false;
            if (UserMenuList != null && UserMenuList.Count() > 0)
            {
                foreach (var item in UserMenuList)
                {
                    if (enumId == item.MenuId)
                    {
                        isEnable = true;
                        break;
                    }
                }
            }
            else
            {
                isEnable = false;
            }
            return isEnable;
        }

        /// <summary>
        /// 保存用户权限
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="menuIds"></param>
        public void SaveUserPermission(int userId, IEnumerable<int> menuIds)
        {
            var dbtran = _userRepository.BeginTransaction();
            try
            {
                // 删除原权限
                _userRepository.DeleteList(new { UserId = userId }, dbtran);
                if (menuIds != null && menuIds.Count() > 0)
                {
                    // 添加新权限
                    foreach (int menuId in menuIds)
                    {
                        _userRepository.Execute(
                            sql: $"INSERT INTO Sys_User_Menu (UserId, MenuId) VALUES ({userId}, {menuId})",
                            transaction: dbtran);
                    }
                }
                dbtran.Commit();
            }
            catch (Exception)
            {
                dbtran.Rollback();
                throw;
            }
            finally
            {
                dbtran.Dispose();
            }
        }

        #endregion

        #region 获取有序菜单列表
        public IEnumerable<Menu> GetMenuList()
        {
            // 获取全部未删除的启用的菜单/按钮
            var list = _repository.GetList(new { IsDeleted = false, IsEnable = true }).ToList();
            var menuList = new List<Menu>();
            GetChild(0, list, ref menuList);
            return menuList;
        }
        protected void GetChild(int parentId, List<Menu> allList, ref List<Menu> codeList)
        {
            var list = allList.FindAll(p => p.ParentId == parentId).OrderBy(p => p.SortIndex).ToList();
            if (list.LongCount() > 0)
            {
                foreach (Menu item in list)
                {
                    codeList.Add(item);
                    GetChild(item.Id, allList, ref codeList);
                }
            }
        }
        #endregion

        #endregion

        #region 权限获取

        /// <summary>
        /// 获取权限列表（菜单及按钮）
        /// 启用且未删除的
        /// </summary>
        public IEnumerable<AuthorityMenuDto> GetAuthorityList()
        {
            IEnumerable<AuthorityMenuDto> list = null;

            // 获取当前用户
            LoginUser currentUser = UserAuthentication.GetCurrentUser();

            // 读取用户菜单权限Session的值
            object data = ZSession.Get(ZConfig.GetConfigString("MenuSessionName"));
            if (data != null)
            {
                list = data as IEnumerable<AuthorityMenuDto>;
            }
            else
            {
                string whereConditions = @"where Id in (select rmt.MenuId from Sys_RoleMenu rmt 
                left join Sys_Role rt on rt.Id=rmt.RoleId
                left join Sys_UserRole urt on urt.RoleId=rt.Id
                where urt.UserId=@UserId and rt.IsDeleted=0) AND IsEnable=1 AND IsDeleted=0";
                var menuList = _repository.GetList(whereConditions, new { @UserId = currentUser.UserID });
                list = Mapper.Map<IEnumerable<AuthorityMenuDto>>(menuList);

                // 存入Session
                ZSession.Add(ZConfig.GetConfigString("MenuSessionName"), list);
            }

            return list;
        }

        /// <summary>
        /// 获取权限菜单（不含按钮）
        /// </summary>
        /// <returns></returns>
        public IEnumerable<AuthorityMenuDto> GetAuthorityMenus() => GetAuthorityList().Where(p => p.MenuType == 1);

        /// <summary>
        /// 获取所有权限按钮
        /// </summary>
        /// <returns></returns>
        public IEnumerable<AuthorityMenuDto> GetAuthorityButtons() => GetAuthorityList().Where(p => p.MenuType == 2);

        /// <summary>
        /// 获取指定路由页的所有按钮
        /// </summary>
        /// <param name="routeValues"></param>
        /// <returns></returns>
        public IEnumerable<AuthorityMenuDto> GetAuthorityButtons(IDictionary<string, object> routeValues)
        {
            var list = GetAuthorityList();  // 当前用户所有权限菜单

            string area = routeValues["area"]?.ToString(),  // 区域
                controller = routeValues["controller"]?.ToString(), // 控制器
                action = routeValues["action"]?.ToString(); // 方法
            object param = routeValues["id"];  // 参数
            if (area == null || controller == null || action == null)
            {
                return null;
            }

            AuthorityMenuDto menu = null;  // 指定路由的菜单
            // 查找菜单
            foreach (var item in list)
            {
                if (item.MenuArea == area) // 匹配区域
                {
                    if (item.MenuControl == controller) // 匹配控制器
                    {
                        if (item.MenuAction == action)  // 匹配方法
                        {
                            if (param == null)  // 无参数
                            {
                                menu = item;
                                break;
                            }
                            else  // 有参数
                            {
                                if (item.MenuParam == param.ToString())  // 匹配参数
                                {
                                    menu = item;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            if (menu == null)
            {
                return null;
            }

            return list.Where(p => p.ParentId == menu.Id && p.MenuType == 2);
        }

        #endregion

        #region 权限验证

        /// <summary>
        /// 验证权限
        /// </summary>
        /// <param name="urlList"></param>
        /// <returns></returns>
        public bool CheckAuthority(string url)
        {
            // TODO: 管理员无需验证

            IEnumerable<AuthorityMenuDto> authorities = GetAuthorityList();
            // 判断当前用户菜单权限中是否含有此待验证权限
            foreach (var item in authorities)
            {
                if (item.MenuUrl == url)
                {
                    return true;
                }
            }
            return false;
        }

        #endregion
    }
}
